package ecnu.ecgbackend.service.impl;

import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ecnu.ecgbackend.config.redis.RedisService;
import ecnu.ecgbackend.dao.*;
import ecnu.ecgbackend.entity.*;
import ecnu.ecgbackend.service.DiagnosisUserService;
import ecnu.ecgbackend.utils.Result;
import ecnu.ecgbackend.utils.SmsSender;
import ecnu.ecgbackend.vo.*;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Transactional
public class DiagnosisUserServiceImpl extends ServiceImpl<UserMapper, User> implements DiagnosisUserService {
    @Resource
    UserMapper userMapper;
    @Resource
    PatientMapper patientMapper;
    @Resource
    DoctorMapper doctorMapper;
    @Resource
    DeveloperMapper developerMapper;
    @Resource
    RedisService redisService;
    @Resource
    ArtificialDiagnosisMapper artificialDiagnosisMapper;
    @Resource
    RawDataMapper rawDataMapper;

    @Override
    public User findUserByUserName(String userName) {
        QueryWrapper<User> queryWrapper=new QueryWrapper<User>();
        queryWrapper.eq("username",userName);
        return baseMapper.selectOne(queryWrapper);
    }
    public boolean isUsernameUsed(User _user,User user){
        User preUser=userMapper.selectById(_user.getId());
        System.out.println("preUser: "+preUser.toString());
        System.out.println("user: "+user.toString());
        List<String> usernames=userMapper.selectList(new QueryWrapper<>()).stream().map(User::getUsername).collect(Collectors.toList());
        if(!user.getUsername().equals(preUser.getUsername()) && usernames.contains(user.getUsername())){
            return true;
        }
        return false;
    }

    @Override
    public Result editPatientInfo(User user, Patient patient) {
        User _user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if(isUsernameUsed(_user,user)){
            return Result.error().message("该用户名已被使用！");
        }
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",_user.getId())
                .set("username",user.getUsername())
                .set("real_name",user.getRealName())
                .set("age",user.getAge())
                .set("gender",user.getGender())
                .set("email",user.getEmail());
        UpdateWrapper<Patient> patientUpdateWrapper=new UpdateWrapper<>();
        patientUpdateWrapper.eq("id",_user.getId())
                .set("health_condition",patient.getHealthCondition())
                .set("integral",patient.getIntegral());
        int isUserUpdate=userMapper.update(null,updateWrapper);
        int isPatientUpdate=patientMapper.update(null,patientUpdateWrapper);
        if(isUserUpdate > 0 && isPatientUpdate > 0){
            return Result.ok().message("用户信息修改成功！");
        }
        return Result.error().message("用户信息修改失败");
    }

    @Override
    public Result editDoctorInfo(User user, Doctor doctor) {
        User _user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if(isUsernameUsed(_user,user)){
            return Result.error().message("该用户名已被使用！");
        }
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",_user.getId())
                .set("username",user.getUsername())
                .set("real_name",user.getRealName())
                .set("age",user.getAge())
                .set("gender",user.getGender())
                .set("email",user.getEmail());
        UpdateWrapper<Doctor> doctorUpdateWrapper=new UpdateWrapper<>();
        doctorUpdateWrapper.eq("id",_user.getId())
                .set("license_number",doctor.getLicenseNumber())
                .set("specialization",doctor.getSpecialization())
                .set("experience_years",doctor.getExperienceYears())
                .set("education",doctor.getEducation())
                .set("certification",doctor.getCertification())
                .set("hospital_affiliation",doctor.getHospitalAffiliation())
                .set("department",doctor.getDepartment())
                .set("consultation_fee",doctor.getConsultationFee());
        int isUserUpdate=userMapper.update(null,updateWrapper);
        int isDoctorUpdate=doctorMapper.update(null,doctorUpdateWrapper);
        if(isUserUpdate > 0 && isDoctorUpdate > 0){
            return Result.ok().message("用户信息修改成功！");
        }
        return Result.error().message("用户信息修改失败");
    }

    @Override
    public Result editDeveloperInfo(User user, Developer developer) {
        User _user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if(isUsernameUsed(_user,user)){
            return Result.error().message("该用户名已被使用！");
        }
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",_user.getId())
                .set("username",user.getUsername())
                .set("real_name",user.getRealName())
                .set("age",user.getAge())
                .set("gender",user.getGender())
                .set("email",user.getEmail());
        UpdateWrapper<Developer> developerUpdateWrapper=new UpdateWrapper<>();
        developerUpdateWrapper.eq("id",_user.getId())
                .set("company",developer.getCompany())
                .set("department",developer.getDepartment())
                .set("position",developer.getPosition())
                .set("work_location",developer.getWorkLocation())
                .set("joining_date",developer.getJoiningDate())
                .set("integral",developer.getIntegral());
        int isUserUpdate=userMapper.update(null,updateWrapper);
        int isDeveloperUpdate=developerMapper.update(null,developerUpdateWrapper);
        if(isUserUpdate > 0 && isDeveloperUpdate > 0){
            return Result.ok().message("用户信息修改成功！");
        }
        return Result.error().message("用户信息修改失败");
    }

    @Override
    public Result editAminInfo(User user) {
        User _user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if(isUsernameUsed(_user,user)){
            return Result.error().message("该用户名已被使用！");
        }
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",_user.getId())
                .set("username",user.getUsername())
                .set("real_name",user.getRealName())
                .set("age",user.getAge())
                .set("gender",user.getGender())
                .set("email",user.getEmail());
        if(userMapper.update(null,updateWrapper)>0){
            return Result.ok().message("用户信息修改成功！");
        }
        return Result.error().message("用户信息修改失败");
    }

    @Override
    public Result editPhone(String phone, String code) {
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String _code=redisService.get(phone);
        if(_code==null){
            return Result.error().message("验证码已失效");
        }
        if(!code.equalsIgnoreCase(_code)){
            return Result.error().message("验证码错误");
        }
        List<String> phones=userMapper.selectList(new QueryWrapper<User>()).stream().map(User::getPhone).collect(Collectors.toList());
        if(phones.contains(phone)){
            return Result.error().message("该手机号已被使用");
        }
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",user.getId())
                .set("phone",phone);
        if(userMapper.update(null,updateWrapper)>0){
            return Result.ok().message("手机号修改成功！");
        }
        return Result.error().message("手机号修改失败");
    }

    @Override
    public Object getUserInfo() {
        User _user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        User user=userMapper.selectById(_user.getId());
        String role=user.getRole();
        if(role.equalsIgnoreCase("patient")){
            Patient patient=patientMapper.selectById(_user.getId());
            return new PatientVo(user,patient);
        }else if(role.equalsIgnoreCase("doctor")){
            Doctor doctor=doctorMapper.selectById(_user.getId());
            return new DoctorVo(user,doctor);
        }else if(role.equalsIgnoreCase("developer")){
            Developer developer=developerMapper.selectById(_user.getId());
            return new DeveloperVo(user,developer);
        }else {
            return user;
        }
    }

    @Override
    public boolean editDoctorCertify(MultipartFile multipartFile) throws IOException {
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        UpdateWrapper<Doctor> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",user.getId())
                .set("license",multipartFile.getBytes());
        if(doctorMapper.update(null,updateWrapper)>0){
            return true;
        }
        return false;
    }

    @Override
    public Integer getIntegral() {
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String role=user.getRole();
        if(role.equals("patient")){
            return patientMapper.selectById(user.getId()).getIntegral();
        }else if(role.equals("developer")){
            return developerMapper.selectById(user.getId()).getIntegral();
        }
        return -1;
    }

    @Override
    public Object getUserInfoByIdAndRole(int id,String role) {
        if(role.equalsIgnoreCase("patient")){
            return patientMapper.selectById(id);
        }else if(role.equalsIgnoreCase("doctor")){
            return doctorMapper.selectById(id);
        }else if(role.equalsIgnoreCase("developer")){
            return developerMapper.selectById(id);
        }else{
            return null;
        }
    }

    @Override
    public Map<String, Object> pageUserList(String category, String username, int pageNum, int pageSize) {
        Page<User> page=new Page<>(pageNum,pageSize);
        List<User> users=null;
        Integer number=1;
        Map<String,Object> result=new HashMap<>();
        if(username!=null && username.length()>0){
            users= userMapper.selectList(new QueryWrapper<User>().eq("username",username).ne("role","admin"));
            number=1;
            result.put("users",users);
            result.put("number",number);
            return result;
        }
        if(category.equals("deleted")){
            users= userMapper.selectPage(page,new QueryWrapper<User>().ne("role","admin").eq("is_delete",1)).getRecords();
            number=userMapper.selectList(new QueryWrapper<User>().ne("role","admin").eq("is_delete",1)).size();
        }else if(category.equals("disabled")){
            users= userMapper.selectPage(page,new QueryWrapper<User>().ne("role","admin").eq("is_enabled",false)).getRecords();
            number=userMapper.selectList(new QueryWrapper<User>().ne("role","admin").eq("is_enabled",false)).size();
        }else {
            users= userMapper.selectPage(page,new QueryWrapper<User>().ne("role","admin")).getRecords();
            number=userMapper.selectList(new QueryWrapper<User>().ne("role","admin")).size();
        }
        result.put("users",users);
        result.put("number",number);
        return result;
    }

    @Override
    public boolean editDoctorCertifiedTrue(int id) {
        UpdateWrapper<Doctor> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",id).set("is_certified",true);
        if(doctorMapper.update(null,updateWrapper)>0){
            return true;
        }
        return false;
    }

    @Override
    public boolean editDoctorCertifiedFalse(int id) {
        UpdateWrapper<Doctor> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",id).set("is_certified",false);
        if(doctorMapper.update(null,updateWrapper)>0){
            return true;
        }
        return false;
    }

    @Override
    public boolean editLockAccount(int id) {
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",id).set("is_account_non_locked",false);
        if(userMapper.update(null,updateWrapper)>0){
            return true;
        }
        return false;
    }

    @Override
    public boolean editUnlockAccount(int id) {
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",id).set("is_account_non_locked",true);
        if(userMapper.update(null,updateWrapper)>0){
            return true;
        }
        return false;
    }

    @Override
    public boolean editEnableAccount(int id) {
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",id).set("is_enabled",true);
        if(userMapper.update(null,updateWrapper)>0){
            return true;
        }
        return false;
    }

    @Override
    public boolean editDisableAccount(int id) {
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",id).set("is_enabled",false);
        if(userMapper.update(null,updateWrapper)>0){
            return true;
        }
        return false;
    }

    @Override
    public boolean editLogoutAccount(int id) {
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",id).set("is_delete",1);
        if(userMapper.update(null,updateWrapper)>0) {
            return true;
        }
        return false;
    }

    @Override
    public boolean editRestoreAccount(int id) {
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",id).set("is_delete",0);
        if(userMapper.update(null,updateWrapper)>0) {
            return true;
        }
        return false;
    }

    @Override
    public boolean editAccountExpired(int id) {
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",id).set("is_account_non_expired",false);
        if(userMapper.update(null,updateWrapper)>0) {
            return true;
        }
        return false;
    }

    @Override
    public boolean editAccountUnexpired(int id) {
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",id).set("is_account_non_expired",true);
        if(userMapper.update(null,updateWrapper)>0) {
            return true;
        }
        return false;
    }

    @Override
    public boolean editPasswordExpired(int id) {
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",id).set("is_credentials_non_expired",false);
        if(userMapper.update(null,updateWrapper)>0) {
            return true;
        }
        return false;
    }

    @Override
    public boolean editPasswordUnexpired(int id) {
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",id).set("is_credentials_non_expired",true);
        if(userMapper.update(null,updateWrapper)>0) {
            return true;
        }
        return false;
    }

    @Override
    public Result editPasswordById(int id, String password) {
        String phone=userMapper.selectById(id).getPhone();
        BCryptPasswordEncoder encoder=new BCryptPasswordEncoder();
        UpdateWrapper<User> updateWrapper=new UpdateWrapper<User>().eq("id",id)
                .set("password",encoder.encode(password));
        if(userMapper.update(null, updateWrapper)>0){
            SendSmsResponse response = SmsSender.sendSms(phone,"心电图辅助诊断系统","SMS_465316096","{\"password\":\""+password+"\"}");
            if(response!=null){
                return Result.ok().message("密码重置成功！\n通知短信发送成功！");
            }else {
                return Result.ok().message("密码重置成功！\n通知短信发送失败");
            }
        }
        return Result.error().message("密码重置失败");
    }

    @Override
    public List<DoctorVo> getDoctors() {
        List<Doctor> doctors=doctorMapper.selectList(new QueryWrapper<Doctor>().eq("is_certified",true));
        List<DoctorVo> doctorVos=doctors.stream().map(item->new DoctorVo(userMapper.selectById(item.getId()),item)).collect(Collectors.toList());
        return doctorVos;
    }

    @Override
    public Result saveArtificialDiagnosis(Long doctorId, String rawDataId) {
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Long patientId=user.getId();
        QueryWrapper<ArtificialDiagnosis> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("patient_id",patientId)
                .eq("raw_data_id",rawDataId);
        if(artificialDiagnosisMapper.selectList(queryWrapper).size()>0){
            return Result.error().message("该心电图数据已申请医生进行诊断");
        }
        ArtificialDiagnosis artificialDiagnosis=new ArtificialDiagnosis(patientId,doctorId,rawDataId,new Date(),"wait",null);
        if(artificialDiagnosisMapper.insert(artificialDiagnosis)>0){
            return Result.ok().message("申请医生诊断成功！");
        }
        return Result.error().message("申请医生诊断失败");
    }

    @Override
    public int getWaitRequestPatient() {
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        QueryWrapper<ArtificialDiagnosis> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("doctor_id",user.getId()).eq("status","wait");
        return artificialDiagnosisMapper.selectList(queryWrapper).size();
    }

    @Override
    public Map<String, Object> pageMyRequestPatient(int pageNum, int pageSize) {
        Map<String,Object> result=new HashMap<>();
        Page<ArtificialDiagnosis> page=new Page<>(pageNum,pageSize);
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        QueryWrapper<ArtificialDiagnosis> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("doctor_id",user.getId()).ne("status","done").ne("status","reject").orderByAsc("patient_id");
        List<ArtificialDiagnosis> artificialDiagnoses=artificialDiagnosisMapper.selectPage(page,queryWrapper).getRecords();
        List<PatientArtificialVo> patientArtificialVos=artificialDiagnoses.stream()
                .map(item->new PatientArtificialVo(userMapper.selectById(item.getPatientId()),item,rawDataMapper.selectOne(new QueryWrapper<RawData>().eq("raw_data_id",item.getRawDataId())))).collect(Collectors.toList());
        int number=artificialDiagnosisMapper.selectList(queryWrapper).size();
        result.put("patient",patientArtificialVos);
        result.put("number",number);
        return result;
    }

    @Override
    public boolean removeArtificialDiagnosis(int patientId, int doctorId, String rawDataId) {
        QueryWrapper<ArtificialDiagnosis> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("patient_id",patientId)
                .eq("doctor_id",doctorId)
                .eq("raw_data_id",rawDataId);
        if(artificialDiagnosisMapper.delete(queryWrapper)>0){
            return true;
        }
        return false;
    }


    @Override
    public boolean editRequestStatusAccept(int patientId, String rawDataId) {
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        UpdateWrapper<ArtificialDiagnosis> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("patient_id",patientId)
                .eq("doctor_id",user.getId())
                .eq("raw_data_id",rawDataId)
                .set("status","accept");
        if(artificialDiagnosisMapper.update(null,updateWrapper)>0){
            return true;
        }
        return false;
    }

    @Override
    public boolean editRequestStatusReject(int patientId, String rawDataId) {
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        UpdateWrapper<ArtificialDiagnosis> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("patient_id",patientId)
                .eq("doctor_id",user.getId())
                .eq("raw_data_id",rawDataId)
                .set("status","reject");
        if(artificialDiagnosisMapper.update(null,updateWrapper)>0){
            return true;
        }
        return false;
    }

    @Override
    public Map<String, Object> getHistoryService(String category, int pageNum, int pageSize) {
        Map<String,Object> result=new HashMap<>();
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Page<RawData> page=new Page<>(pageNum,pageSize);
        QueryWrapper<RawData> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("patient_id",user.getId()).orderByDesc("update_date");
        if(!category.equals("none")){
            queryWrapper.eq("category",category);
        }
        int number=rawDataMapper.selectList(queryWrapper).size();
        List<RawData> rawDataList=rawDataMapper.selectPage(page,queryWrapper).getRecords();
        List<Map<String,Object>> list= rawDataList.stream().map(item->{
            Map<String,Object> record=new HashMap<>();
            record.put("rawData",item);
            ArtificialDiagnosis artificialDiagnosis=artificialDiagnosisMapper.selectOne(
                    new QueryWrapper<ArtificialDiagnosis>().eq("raw_data_id",item.getRawDataId())
                            .eq("patient_id",item.getPatientId()));
            record.put("artificialDiagnosis",artificialDiagnosis);
            if(artificialDiagnosis==null){
                record.put("doctorName",null);
            }else {
                record.put("doctorName", userMapper.selectById(artificialDiagnosis.getDoctorId()).getRealName());
            }
            return record;
        }).collect(Collectors.toList());
        result.put("history",list);
        result.put("number",number);
        return result;
    }

    public Map<String,Object> minusPatientIntegral(){
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Map<String,Object> update=new HashMap<>();
        UpdateWrapper<Patient> updateWrapper=new UpdateWrapper<>();
        int integral=patientMapper.selectById(user.getId()).getIntegral()-1;
        updateWrapper.eq("id",user.getId()).set("integral",integral);
        boolean success=patientMapper.update(null,updateWrapper)>0;
        update.put("success",success);
        update.put("integral",integral);
        return update;
    }
    public Map<String,Object> minusDeveloperIntegral(){
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Map<String,Object> update=new HashMap<>();
        UpdateWrapper<Developer> updateWrapper=new UpdateWrapper<>();
        int integral=developerMapper.selectById(user.getId()).getIntegral()-1;
        updateWrapper.eq("id",user.getId()).set("integral",integral);
        boolean  success=developerMapper.update(null,updateWrapper)>0;
        update.put("success",success);
        update.put("integral",integral);
        return update;
    }

    @Override
    public Map<String, Object> minusIntegral() {
        User user= (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String role=user.getRole();
        if(role.equals("patient")){
            return minusPatientIntegral();
        }else if(role.equals("developer")){
            return minusDeveloperIntegral();
        }
        return new HashMap<>();
    }
    boolean editPatientIntegral(int id,int integral){
        UpdateWrapper<Patient> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",id).set("integral",integral);
        if(patientMapper.update(null,updateWrapper)>0){
            return true;
        }
        return false;
    }
    boolean editDeveloperIntegral(int id,int integral){
        UpdateWrapper<Developer> updateWrapper=new UpdateWrapper<>();
        updateWrapper.eq("id",id).set("integral",integral);
        if(developerMapper.update(null,updateWrapper)>0){
            return true;
        }
        return false;
    }

    @Override
    public boolean editIntegral(int id, int integral) {
        User user=userMapper.selectById(id);
        if(user.getRole().equalsIgnoreCase("patient")){
            return editPatientIntegral(id,integral);
        }else if(user.getRole().equalsIgnoreCase("developer")){
            return editDeveloperIntegral(id,integral);
        }
        return false;
    }
}
